package com.leyou.order.service;


import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.common.utils.UserHolder;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.dto.vo.OrderDetailVO;
import com.leyou.order.dto.vo.OrderLogisticsVO;
import com.leyou.order.dto.vo.OrderVO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Transactional
    public Long createOrder(OrderDTO orderDTO) {

        //1.组织Order数据，完成新增，
        Order order = new Order();
        //1.1 订单编号
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);
        //1.2 用户id
        Long userId = UserHolder.getUser();
        order.setUserId(userId);
        //1.3 订单金额相关数据，需要查询商品信息后逐个运算并累加获取
        List<CartDTO> carts = orderDTO.getCarts();
        //1.3.1获取所有订单的id
        List<Long> skuIds = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
        // 1.3.2处理CartDTO为一个map， 其key是skuId；值是num
        Map<Long, Integer> numMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        //1.3.3根据skuid查询出sku
        List<SkuDTO> skuDTOS = itemClient.querySkuByIds(skuIds);
        // 1.3.4定义一个OrderDetail的集合,查询商品信息后，封装为OrderDetail集合，然后新增
        List<OrderDetail> details = new ArrayList<>();
        //1.3.5计算金额的总和
        long total = 0;
        for (SkuDTO skuDTO : skuDTOS) {
            int num = numMap.get(skuDTO.getId());
            //计算总金额
            total += skuDTO.getPrice() * num;
            // 组装OrderDetail
            OrderDetail detail = new OrderDetail();
            detail.setOrderId(orderId);
            detail.setSkuId(skuDTO.getId());
            detail.setNum(num);
            detail.setTitle(skuDTO.getTitle());
            detail.setOwnSpec(skuDTO.getOwnSpec());
            detail.setPrice(skuDTO.getPrice());
            detail.setImage(StringUtils.substringBefore(skuDTO.getImages(),","));
            details.add(detail);
        }
        //1.3.6 填写金额数据
        order.setTotalFee(total);
        order.setPostFee(0L);
        order.setActualFee(total+order.getPostFee() /* - 优惠金额*/);
        order.setPaymentType(orderDTO.getPaymentType());

        //1.4 订单状态数据
        order.setStatus(OrderStatusEnum.INIT.value());
        //1.5 写到order数据库
        int count = orderMapper.insertSelective(order);
        if (count != 1){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        //2. 组织OrderDetail数据，完成新增
        count = orderDetailMapper.insertDetailList(details);
        if (count != details.size()){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        //3. 组织OrderLogistics数据，完成新增
        //3.1 需要查询到收货人地址,根据地址id
        AddressDTO address = userClient.queryAddressById(userId, orderDTO.getAddressId());
        //3.2填写物流信息
        OrderLogistics orderLogistics = BeanHelper.copyProperties(address,OrderLogistics.class);
        orderLogistics.setOrderId(orderId);
        //3.2然后根据收货人地址，封装OrderLogistics后，完成新增
        count = orderLogisticsMapper.insertSelective(orderLogistics);
        if (count != 1){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
        //4. 下单完成后，商品对应库存应该减掉
        itemClient.minusStock(numMap);
        return orderId;
    }


    public List<OrderDetailVO> queryDetailByOrderId(Long orderId){
        //查询订单详情
        OrderDetail detail = new OrderDetail();
        detail.setOrderId(orderId);
        List<OrderDetail> details = orderDetailMapper.select(detail);
        if (CollectionUtils.isEmpty(details)){
            throw new LyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
        }
        return BeanHelper.copyWithCollection(details,OrderDetailVO.class);

    }

    public OrderLogisticsVO queryLogisticsById(Long orderId){
        //查询物流信息
        OrderLogistics logistics = orderLogisticsMapper.selectByPrimaryKey(orderId);
        if (logistics == null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return BeanHelper.copyProperties(logistics,OrderLogisticsVO.class);

    }




    public OrderVO queryOrderById(Long orderId) {
        //查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //用户id
        Long userId = UserHolder.getUser();
        if (!userId.equals(order.getUserId())){
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        //转换为VO
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        //查询详情
        List<OrderDetailVO> detailVOS = queryDetailByOrderId(orderId);

        //查询物流信息
        OrderLogisticsVO logisticsVO = queryLogisticsById(orderId);

        //返回
        orderVO.setDetailList(detailVOS);
        orderVO.setLogistics(logisticsVO);
        return orderVO;
    }


    @Autowired
    private PayHelper payHelper;
    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String KEY_PATTERN = "order:url:id:";
    public String getPayUrl(Long orderId) {
        // 先看是否已经生成过：

        String key = KEY_PATTERN + orderId;
        String cacheUrl = redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(cacheUrl)){
            return cacheUrl;
        }
        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        // 判断订单状态
        if (!order.getStatus().equals(OrderStatusEnum.INIT.value())){
            // 订单已经支付过了，订单状态异常
            throw new LyException(ExceptionEnum.INVALID_ORDER_STATUS);
        }
        // 支付金额，测试时写1
//        Long totalFee = order.getTotalFee();
        Long actualPay = /*order.getActualPay()*/ 1L;
        // 商品描述
        String desc = "【乐优商城】商品信息";
        String url = payHelper.getPayUrl(desc, orderId, actualPay);
        // 存入redis，设置有效期为 2小时
        redisTemplate.opsForValue().set(key,url,2, TimeUnit.HOURS);

        return url;
    }

    public void handleNotify(Map<String, String> data) {
        //校验签名
        payHelper.checkSignature(data);
        //校验业务标示
        payHelper.checkSignature(data);
        //获取结果中的订单信息
        String outTradeNo = data.get("out_trade_no"); //商户订单号
        String totalFeeStr = data.get("total_fee"); //订单金额
        if (StringUtils.isBlank(outTradeNo) || StringUtils.isBlank(totalFeeStr)){
            throw new LyException(ExceptionEnum.INVALID_PARAM_ERROR);
        }
        //转换订单数据
        Long orderId = Long.valueOf(outTradeNo);
        Long totalFee = Long.valueOf(totalFeeStr);
        //校验订单状态，保证接口幂等
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (!order.getStatus().equals(OrderStatusEnum.INIT.value())){
            //订单已经支付了，不要再执行了
            return;
        }
        //校验订单金额
        if (!totalFee.equals( /*order.getTotalFee()*/ 1L)){
            throw new LyException(ExceptionEnum.INVALID_PARAM_ERROR);
        }
        //支付成功，修改订单状态为已支付
        Order record = new Order();
        record.setStatus(OrderStatusEnum.PAY_UP.value());
        record.setOrderId(orderId);
        record.setPayTime(new Date());
        int count = orderMapper.updateByPrimaryKeySelective(record);
        if (count != 1){
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }

        log.info("【订单服务】接受微信支付通知成功！");
    }

    public Integer queryPayState(Long id) {

        Order order = orderMapper.selectByPrimaryKey(id);
        if (order == null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

        return order.getStatus();
    }
}
